package org.alma.opengl

import javax.swing._
import javax.media.opengl._
import java.awt.{Dimension, BorderLayout}
import java.awt.event.{KeyListener, WindowAdapter, WindowEvent, KeyEvent}
import com.sun.opengl.util._
import scala.collection.mutable.ListBuffer

object GLDisplay
{
  private val frame = new JFrame
  private val caps = new GLCapabilities
  private var canvas: GLCanvas = null
  var defaultSize = new Dimension(640, 480)
  
  def apply(title: String, size: Dimension, renderer: GLEventListener) =
  {
    frame.setTitle(title)
    frame.setSize(size)
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE)
    frame.setLocationRelativeTo(null)
    
    caps.setHardwareAccelerated(true)
    caps.setDoubleBuffered(true)
    
    canvas = new GLCanvas(caps)
    canvas.setSize(size.width, size.height)
    canvas.addGLEventListener(renderer)
    
    frame.getContentPane.setLayout(new BorderLayout)
    frame.getContentPane.add(canvas, BorderLayout.CENTER)
    frame.addKeyListener(KeyboardListeners)
    
    frame.addWindowListener(new WindowAdapter
    {
      override def windowClosing(e: WindowEvent) = stop
    })
  }
  
  def apply(title: String, renderer: GLEventListener) : Unit = apply(title, defaultSize, renderer)
  
  def start =
  {
    canvas.requestFocus
    try
    { 
      SwingUtilities.invokeLater
      {
        new Runnable
        {
          def run = frame.setVisible(true)
        }
      }
    }
    
    catch
    {
      case e: Exception =>
      ExceptionHandler.handleDialog(e)
    }
    
  }
  
  def stop =
  {
    frame.dispose
    System.exit(0)
  }
  
  def size = frame.getSize
  def size(size: Dimension) = frame.setSize(size)
  
  def title = frame.getTitle
  def title(title: String) = frame.setTitle(title)
  
  object ExceptionHandler 
  {
    def handle(e: Exception, action: => Unit)
    {
      SwingUtilities.invokeAndWait
      {
        new Runnable
        {
          def run = action
        }
      }
    }
    
    def handleDialog(e: Exception)
    {
      def dia = JOptionPane.showMessageDialog(frame, e.getMessage, "Error", JOptionPane.ERROR_MESSAGE)
      handle(e, dia)
    }
  }
  
  object KeyboardListeners extends KeyListener
  {
    private val listeners = new ListBuffer[KeyListener]
    
    
    def +=(listener: KeyListener) = listeners += listener
    
    def -=(listener: KeyListener) = listeners -= listener
    
    override def keyReleased(e: KeyEvent) =
    {
      listeners.foreach(l => l.keyReleased(e))
    }
    
    override def keyPressed(e: KeyEvent) =
    {
      listeners.foreach(l => l.keyPressed(e))
    }
    
    override def keyTyped(e: KeyEvent) =
    {
      listeners.foreach(l => l.keyTyped(e))
    }
  }
  
}
